package dev.ece.suit.ui;

import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import org.apache.commons.lang3.StringUtils;

import dev.ece.core.cells.model.AbstractUI;
import dev.ece.core.shader.DefaultTextureShader;
import dev.ece.core.texture.Texture;
import dev.ece.suit.text.TextLibrary;
import dev.ece.suit.ui.event.ButtonListener;
import dev.ece.suit.ui.shader.ButtonTextureShader;
import dev.ece.suit.ui.utils.Alignment;
import dev.ece.util.lib.IntOffset;
import dev.ece.util.lib.IntRectangle;
import dev.ece.util.lib.Rectangle;
import dev.ece.util.lib.Vector2f;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.lib.Vector4f;
import dev.ece.util.obj.ObjectCount;
import dev.ece.util.tools.Camera;

public class Button extends ContentItem implements Selectable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1248848254934256108L;

	private Collection<ButtonListener> buttonListeners = Collections.synchronizedCollection(new ArrayList<ButtonListener>());
	
	private final Vector2f pressedOffset = new Vector2f();
	
	private Vector4f selectedColor = new Vector4f(1, 1, 1, 0.7f);
	
	private SelectableGroup<Button> selectableGroup;
	
	private boolean pressed;
	
	private boolean selected;
	
	private boolean disabled;
	
	private TextLibrary textLibrary = Fonts.getSystemTextLibrary();
	
	private Vector4f fontColor = new Vector4f(1, 1, 1, 1);
	
	private String text;
	
	private int fontSize;
	
	private int alignment = Alignment.CENTER;
	
	private final Vector3f textPosition = new Vector3f();
	
	public Button(String background, float width, float height) throws IOException {
		super(background, width, height);
	}
	
	public Button(String background, float width, float height, IntRectangle centerClipping) throws IOException {
		super(background, width, height, centerClipping);
	}

	public Button(String background, float width, float height, IntOffset centerClipping) throws IOException {
		super(background, width, height, centerClipping);
	}

	public Button(String background, IntRectangle textureClipping, float width, float height, IntRectangle centerClipping)
			throws IOException {
		super(background, textureClipping, width, height, centerClipping);
	}
	
	public Button(String background, IntRectangle textureClipping, float width, float height, IntOffset centerClipping)
			throws IOException {
		super(background, textureClipping, width, height, centerClipping);
	}

	public Button(String background, IntRectangle textureClipping, float width, float height) throws IOException {
		super(background, textureClipping, width, height);
	}

	public Button(AbstractUI<Float> ui, BufferedImage background) {
		super(ui, background);
	}

	public Button(AbstractUI<Float> ui, ObjectCount<Texture> background) {
		super(ui, background);
	}

	public Button(AbstractUI<Float> ui, String background) throws IOException {
		super(ui, background);
	}

	public Button(BufferedImage image, float width, float height) {
		super(image, width, height);
	}

	public Button(BufferedImage image, float width, float height, IntRectangle centerClipping) {
		super(image, width, height, centerClipping);
	}

	public Button(BufferedImage image, float width, float height, IntOffset centerClipping) {
		super(image, width, height, centerClipping);
	}

	public Button(BufferedImage image, IntRectangle textureClipping, float width, float height, IntRectangle centerClipping) {
		super(image, textureClipping, width, height, centerClipping);
	}

	public Button(BufferedImage image, IntRectangle textureClipping, float width, float height,
			IntOffset centerClipping) {
		super(image, textureClipping, width, height, centerClipping);
	}

	public Button(BufferedImage image, IntRectangle textureClipping, float width, float height) {
		super(image, textureClipping, width, height);
	}

	public Button(ObjectCount<Texture> background, float width, float height) {
		super(background, width, height);
	}

	public Button(ObjectCount<Texture> background, float width, float height, IntRectangle centerClipping) {
		super(background, width, height, centerClipping);
	}

	public Button(ObjectCount<Texture> background, float width, float height, IntOffset centerClipping) {
		super(background, width, height, centerClipping);
	}

	public Button(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height,
			IntRectangle centerClipping) {
		super(background, textureClipping, width, height, centerClipping);
	}

	public Button(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height,
			IntOffset centerClipping) {
		super(background, textureClipping, width, height, centerClipping);
	}

	public Button(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height) {
		super(background, textureClipping, width, height);
	}

	@Override
	protected void setup() {
		super.setup();
		this.fontSize = (int) (this.getHeight() * 2 / 3);
	}

	public int getFontSize() {
		return fontSize;
	}

	public void setFontSize(int fontSize) {
		if(fontSize <= 0) {
			throw new IllegalArgumentException("fontSize必须大于0");
		}
		if(textLibrary == null) {
			throw new IllegalArgumentException("textLibrary不能为null");
		}
		this.fontSize = fontSize;
		this.computeTextPostion();
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		if(textLibrary == null) {
			throw new IllegalArgumentException("textLibrary不能为null");
		}
		this.text = text;
		this.computeTextPostion();
	}

	public int getAlignment() {
		return alignment;
	}

	public void setAlignment(int alignment) {
		this.alignment = alignment;
		this.computeTextPostion();
	}
	
	protected void computeTextPostion() {
		if(StringUtils.isNotBlank(getText())) {
			float textWidth = getTextLibrary().getCharsWidth(getText(), getFontSize());
			float textHeight = getTextLibrary().getLineHeight(getFontSize());
			Rectangle rect = getViewRectangle();
			getTextPosition().setY(textHeight / 2);
			switch(getAlignment()) {
				case Alignment.CENTER:
					getTextPosition().setX(-textWidth / 2);
					return;
				case Alignment.RIGHT:
					getTextPosition().setX(rect.right - textWidth);
					return;
				default:
					getTextPosition().setX(rect.left);
			}
		}
	}
	
	public Vector4f getFontColor() {
		return fontColor;
	}

	protected Vector3f getTextPosition() {
		return textPosition;
	}

	public void setFontColor(Vector4f fontColor) {
		if(fontColor == null) {
			throw new IllegalArgumentException("fontColor不能为null");
		}
		this.fontColor = fontColor;
	}

	public TextLibrary getTextLibrary() {
		return textLibrary;
	}

	public void setTextLibrary(TextLibrary textLibrary) {
		if(textLibrary == null) {
			throw new IllegalArgumentException("textLibrary不能为null");
		}
		this.textLibrary = textLibrary;
		this.computeTextPostion();
	}

	@Override
	protected DefaultTextureShader createDefaultTextureShader() {
		try {
			return ButtonTextureShader.getDefaultButtonTextureShader();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	protected void glUseShader() {
		ButtonTextureShader shader = (ButtonTextureShader) getDefaultTextureShader();
		shader.glUseProgram();
		shader.glModelViewProjectMatrix();
		shader.glTexture(getBackground());
		shader.glDisabled(isDisabled());
		shader.glPressed(isPressed(), getPressedOffset());
		shader.glSelected(isSelected(), getSelectedColor());
	}
	
	@Override
	protected void renderChildren(Camera camera) {
		renderText();
		super.renderChildren(camera);
	}

	protected void renderText() {
		//绘制文字
		if(StringUtils.isNotBlank(getText())) {
			getTextLibrary().renderSimpleText(getText(), getFontSize(), getFontColor(), getTextPosition());
		}
	}
	
	public void select() {
		if(this.isDisabled()) {
			return;
		}
		if(getSelectableGroup() != null) {
			getSelectableGroup().select(this);
		}
	}
	
	@Override
	public boolean isSelected() {
		return selected;
	}

	@Override
	public void selected() {
		setSelected(true);
	}

	@Override
	public void unselect() {
		setSelected(false);
	}

	public boolean isDisabled() {
		return disabled;
	}

	public void setDisabled(boolean disabled) {
		this.disabled = disabled;
	}

	public void setPressedOffset(float x, float y) {
		getPressedOffset().set(x, y);
	}
	
	public void setPressedOffset(int x, int y) {
		getPressedOffset().set(x / (float) this.getBackground().getWidth(), y / (float) this.getBackground().getHeight());
	}
	
	protected Vector2f getPressedOffset() {
		return this.pressedOffset;
	}

	public SelectableGroup<Button> getSelectableGroup() {
		return selectableGroup;
	}

	public void setSelectableGroup(SelectableGroup<Button> selectableGroup) {
		if(this.selectableGroup != null) {
			this.selectableGroup.removeSelection(this);
		}
		this.selectableGroup = selectableGroup;
		if(this.selectableGroup != null) {
			this.selectableGroup.addSelection(this);
		}
	}

	public Vector4f getSelectedColor() {
		return selectedColor;
	}

	public void setSelectedColor(Vector4f selectedColor) {
		if(selectedColor == null) {
			throw new IllegalArgumentException("参数selectedColor不能为null");
		}
		this.selectedColor = selectedColor;
	}

	protected Collection<ButtonListener> getButtonListeners() {
		return buttonListeners;
	}

	public void addButtonListener(ButtonListener listener) {
		if(!containsButtonListener(listener)) {
			getButtonListeners().add(listener);
		}
	}
	
	public boolean containsButtonListener(ButtonListener listener) {
		return getButtonListeners().contains(listener);
	}
	
	public void removeButtonListener(ButtonListener listener) {
		getButtonListeners().remove(listener);
	}
	
	public int buttonListenersLength() {
		return getButtonListeners().size();
	}
	
	public boolean isPressed() {
		return pressed;
	}

	protected void setPressed(boolean pressed) {
		this.pressed = pressed;
	}

	protected void setSelected(boolean selected) {
		this.selected = selected;
	}

	@Override
	public void click() {
		if(this.isDisabled()) {
			return;
		}
		for(ButtonListener listener: buttonListeners) {
			listener.onClicked(this);
		}
		super.click();
	}

	public void press() {
		if(!this.isPressed()) {
			this.setPressed(true);
			for(ButtonListener listener: buttonListeners) {
				listener.onPressed(this);
			}
		}
	}
	
	public void release() {
		if(this.isPressed()) {
			this.setPressed(false);
			for(ButtonListener listener: buttonListeners) {
				listener.onReleased(this);
			}
		}
	}
	
	@Override
	public boolean mouseButtonDown(int button, float x, float y) {
		if(this.isDisabled()) {
			return true;
		}
		return super.mouseButtonDown(button, x, y);
	}

	@Override
	public boolean onMouseButtonDown(int button, float x, float y) {
		this.press();
		this.select();
		super.onMouseButtonDown(button, x, y);
		return true;
	}

	@Override
	public boolean onMouseButtonUp(int button, float x, float y) {
		this.release();
		super.onMouseButtonUp(button, x, y);
		return false;
	}

	@Override
	public void destroy() {
		super.destroy();
		if(selectableGroup != null) {
			this.setSelectableGroup(null);
		}
	}

	@Override
	public void clearup() {
		super.clearup();
		this.buttonListeners.clear();
	}
	
}
